﻿#include "ais_mesh.h"
#include "ais_point.h"
#include "kernel/convex.h"
#include "kernel/transform.h"

CAGD::AIS_Mesh::AIS_Mesh(Handle(TopoMesh) mesh) : m_topoMesh(mesh)
{
    // 创建实例矩阵和修复矩阵
    m_info.insMats.push_back(BMat4x4());
    m_info.fixMats.push_back(BMat4x4());

    // 默认纹理
    m_info.diffuseTex = TEXTURE::YELLOW2D;
    m_info.specularTex = TEXTURE::WHITE2D;
    m_info.reflactTex = TEXTURE::BLACK2D;
    m_info.reflectTex = TEXTURE::BLACK2D;

    // 获得可渲染网格
    m_mesh = mesh->ToTriangleMesh();

    // 创建子节点包围盒
    auto box = Handle(AIS_Box)(new AIS_Box);
    AddChild(box);
    box->UpdateArray();
    m_context.CreateObject(box);

    // 创建质心点，孤立质心点
    m_info.centroid = box->GetBBox().center;
    m_info._centroid = m_info.centroid;
    Handle(GeomPoint) center(new GeomPoint(&m_info.centroid));
    Handle(AIS_Point) c(new AIS_Point(center));
    auto &info = c->GetInfo();
    if (m_context.GetInfo().viewMode != ViewMode::CONTROL)
        info.status = AIS_Status::HIDDEN;
    info.smooth = true;
    info.psize = 10;

    m_context.CreateObject(c);
}

bool CAGD::AIS_Mesh::MoveTo(Point pos)
{
    // 隐藏状态不交互，不活跃状态不交互
    if (m_info.status == AIS_Status::HIDDEN || m_info.active == false)
        return false;

    // 临时记录
    bool hang = false;
    auto tmp = m_info.status;
    m_info.status = AIS_Status::NONE;

    // 如果包围盒碰撞才进一步计算
    auto box = dynamic_cast<AIS_Box *>(GetChild(AIS_Type::BOX));
    if (box->Collision(pos))
    {
        float z1 = 0.8;
        auto &context = m_context;
        auto invModel = Transform::Inverted(m_info.modelMat);
        BPnt q1 = Transform::Perform(invModel, context.GetSpacePoint(pos, z1));
        BPnt q2 = Transform::Perform(invModel, context.GetInfo().viewPos);
        BVec v = q1 - q2;

        for (int i = 0; i < m_mesh->triangles.size(); i++)
        {
            const Triangle &triangle = m_mesh->triangles[i];
            std::vector<BPnt> points(
                {m_mesh->vertices[triangle.i], m_mesh->vertices[triangle.j], m_mesh->vertices[triangle.k]});

            if (Convex::InProjectHull(q2, v, points))
            {
                hang = true;
                if (tmp != AIS_Status::TOUCH)
                    m_info.status = AIS_Status::HANG;
                else
                    m_info.status = tmp;

                float d0, d1, d2;
                BPnt2d q0 = m_context.GetScreenPoint(points[0], d0);
                BPnt2d q1 = m_context.GetScreenPoint(points[1], d1);
                BPnt2d q2 = m_context.GetScreenPoint(points[2], d2);

                // 计算深度
                SetDepth((d0 + d1 + d2) / 3);
                break;
            }
        }
    }

    return hang;
}

void CAGD::AIS_Mesh::UpdateInfo()
{
    m_info.size = m_mesh->triangles.size() * 3;
    m_info.modelMat = Transform::Translate(m_info.centroid - m_info._centroid);
}

CAGD::AIS_Type CAGD::AIS_Mesh::GetType() const
{
    return AIS_Type::MESH;
}

Handle(CAGD::TriangleMesh) CAGD::AIS_Mesh::GetMesh() const
{
    return m_mesh;
}

Handle(CAGD::TopoMesh) CAGD::AIS_Mesh::GetTopoMesh() const
{
    return m_topoMesh;
}